package com.iplay.service.hotel.discount;

import java.io.IOException;
import java.text.ParseException;
import java.util.List;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.iplay.component.date.FeastBookingDateFormatter;
import com.iplay.component.excel.ExcelReader;
import com.iplay.component.excel.exception.ExcelIOException;
import com.iplay.dao.hotel.HotelDAO;
import com.iplay.dao.hotel.discount.HotelDiscountDAO;
import com.iplay.dto.ApiResponse;
import com.iplay.dto.ApiResponseMessage;
import com.iplay.dto.hotel.HotelDiscountDTO;
import com.iplay.entity.hotel.discount.HotelDiscountDO;
import com.iplay.service.exception.ResourceNotFoundException;

@Service
public class HotelDiscountServiceImpl implements HotelDiscountService {

	private static final Logger LOGGER = LoggerFactory.getLogger(HotelDiscountServiceImpl.class);

	@Autowired
	private HotelDiscountDAO hotelDiscountDAO;

	@Autowired
	private ExcelReader excelReader;

	@Autowired
	private FeastBookingDateFormatter formatter;

	@Autowired
	private HotelDiscountAsyncTask hotelDiscountAsyncTask;
	
	@Autowired
	private HotelDAO hotelDAO;

	@Override
	public List<HotelDiscountDTO> listDiscounts(int hotelId, long baseDate, Pageable pageable) {
		checkHotelExists(hotelId);
		return hotelDiscountDAO.findByHotelIdAndDateGreaterThanEqual(hotelId, baseDate, pageable).getContent().stream()
				.map(discountDO -> do2DTO(discountDO)).collect(Collectors.toList());
	}

	@Override
	public Page<HotelDiscountDTO> listByHotelId(int hotelId, Pageable pageable) {
		checkHotelExists(hotelId);
		return hotelDiscountDAO.findByHotelId(hotelId, pageable).map(discountDO -> do2DTO(discountDO));
	}

	private HotelDiscountDTO do2DTO(HotelDiscountDO discountDO) {
		return new HotelDiscountDTO(discountDO.getHotelId(), formatter.toDefaultFormattedDate(discountDO.getDate()),
				discountDO.getDiscount());
	}

	@Override
	public boolean saveHotelDiscount(int hotelId, List<HotelDiscount> discounts) {
		try {
			hotelDiscountDAO.save(discounts.stream().map(d -> {
				try {
					return new HotelDiscountDO(hotelId,
							formatter.parseToDateWithDefaultDateFormat(d.getDate()).getTime(), d.getDiscount());
				} catch (ParseException e) {
					e.printStackTrace();
					return null;
				}
			}).filter(d -> d != null).collect(Collectors.toList()));
		} catch (DataIntegrityViolationException e) {
			LOGGER.error(e.getMessage());
		}
		return true;
	}

	@Override
	public ApiResponse<String> saveHotelDiscount(int hotelId, MultipartFile file) {
		checkHotelExists(hotelId);
		try {
			List<HotelDiscount> discounts = excelReader.loadAll(file.getInputStream(), HotelDiscount.class);
			//saveHotelDiscount(hotelId, discounts);
			hotelDiscountAsyncTask.saveHotelDiscount(hotelId, discounts);
		} catch (ExcelIOException | IOException e) {
			LOGGER.error(e.getMessage(), e);
			return ApiResponse.createFailApiResponse(ApiResponseMessage.DISCOUNT_EXCEL_IO_EXCEPTION);
		}
		return ApiResponse.SUCCESSFUL_RESPONSE_WITHOUT_MESSAGE;
	}

	private void checkHotelExists(int hotelId) {
		if (hotelDAO.findOne(hotelId) == null)
			throw new ResourceNotFoundException("Hotel with id:" + hotelId + " doesn't exist");
	}

	@Override
	public List<HotelDiscountDTO> listDiscounts(int hotelId, long start, long end, Pageable pageable) {
		checkHotelExists(hotelId);
		return hotelDiscountDAO.findByHotelIdAndDateGreaterThanEqualAndDateLessThanEqual(hotelId, start, end, pageable)
				.getContent().stream().map(discountDO -> do2DTO(discountDO)).collect(Collectors.toList());
	}
}
